#ifndef _SIGNAL_CLIENT_H_
#define _SIGNAL_CLIENT_H_

#include <stdint.h>

typedef enum {
    signal_error_ok = 0,
    signal_error_fail = 1,
    signal_error_invalid_param = 2,
    signal_error_connect=10,
    signal_error_disconnect=11,
    signal_error_no_msg=12,
}signal_error_e;

typedef struct {
    char *data;
    uint32_t pos;
    uint32_t cap;
}buffer_t;
buffer_t create_buffer_t(uint32_t size);
void free_buffer_t(buffer_t *buffer);
void free_buffer_t_content(buffer_t *buffer);

typedef uint8_t session_id_t;
#define INVALID_SESSION_ID 0

#define SERVER_ADDR_LEN 128
#define COMMON_STR_LEN 64
typedef struct {
    char stun_server[SERVER_ADDR_LEN];
    char turn_server[SERVER_ADDR_LEN];
    char turn_user[COMMON_STR_LEN];
    char turn_pwd[COMMON_STR_LEN];
}ice_info_t;

#define ERROR_INFO_LEN 128
typedef struct {
    int rc;
    char rd[ERROR_INFO_LEN];
}session_error_info_t;

typedef struct {
    buffer_t sdp;
}session_sdp_info_t;

typedef struct {
    unsigned int status;
}session_status_info_t;

typedef struct {
    session_sdp_info_t sdp;
    ice_info_t ice;
}session_create_by_remote_t;

typedef struct {
    buffer_t cands;
}session_ice_cands_update_t;

typedef enum {
    smi_session_created,
    smi_session_created_by_remote,
    smi_remote_sdp_arrived,
    smi_session_closing,
    smi_remote_ice_candidate_update,
    smi_session_error,
    smi_session_status,
}signal_msg_id_t;

typedef struct _signal_msg_t{
    signal_msg_id_t msg_id;
    session_id_t session_id;
    buffer_t data;
    void (*destroy)(struct _signal_msg_t *msg);
}signal_msg_t;

typedef struct _signal_client_opt {
    char url[SERVER_ADDR_LEN];
    char user[COMMON_STR_LEN];
    char pwd[COMMON_STR_LEN];
}signal_client_opt_t;

/* not thread-safe */
typedef struct _signal_client{
    void *priv;
    void (*destroy)(struct _signal_client *client);
    signal_error_e (*login)(struct _signal_client *client);
    signal_error_e (*create_session)(struct _signal_client *client, const char *peer_id, 
                                        session_id_t *out_session_id, ice_info_t *out_ice_info);
    void (*destroy_session)(struct _signal_client *client, session_id_t session_id);
    signal_error_e (*update_local_sdp)(struct _signal_client *client, session_id_t session_id, const char *sdp);
    signal_error_e (*update_ice_candidate)(struct _signal_client *client, session_id_t session_id, const char *sdp);
    signal_error_e (*handle_msg)(struct _signal_client *client, signal_msg_t *out_msg, uint32_t to_in_ms);
    // @return 0: disconnect, 1: connected
    uint8_t (*is_connected)(struct _signal_client *client);

}signal_client_t;

signal_client_t* create_client(signal_client_opt_t *opt);

#endif  /* _SIGNAL_CLIENT_H_ */
